using System;
using stob;
using System.Diagnostics;
using System.IO;
using System.Collections.Generic;
using System.Text;

namespace tests
{
	class MainClass
	{
		private class ExpectedItem{
			public enum EType{
				STRING,
				CHILD_BEGIN,
				CHILD_END
			}
			public EType type;
			public String str;

			public ExpectedItem(EType type, String str){
				this.type = type;
				this.str = str;
			}
		};

		private static void TestParser(){
			var expected = new List<ExpectedItem> ();

			expected.Add (new ExpectedItem (ExpectedItem.EType.STRING, "ttt"));
			expected.Add (new ExpectedItem (ExpectedItem.EType.STRING, "test string"));
			expected.Add (new ExpectedItem (ExpectedItem.EType.STRING, "anot/her string"));
			expected.Add (new ExpectedItem (ExpectedItem.EType.STRING, "unqu/otedString"));
			expected.Add (new ExpectedItem (ExpectedItem.EType.STRING, "string with empty children list"));
			expected.Add (new ExpectedItem (ExpectedItem.EType.CHILD_BEGIN, null));
			expected.Add (new ExpectedItem (ExpectedItem.EType.CHILD_END, null));
			expected.Add (new ExpectedItem (ExpectedItem.EType.STRING, "unquoted_string_with_empty_children_list"));
			expected.Add (new ExpectedItem (ExpectedItem.EType.CHILD_BEGIN, null));
			expected.Add (new ExpectedItem (ExpectedItem.EType.CHILD_END, null));
			expected.Add (new ExpectedItem (ExpectedItem.EType.STRING, "string_interrupted_by_comment"));
			expected.Add (new ExpectedItem (ExpectedItem.EType.STRING, "string_broken_by_comment"));
			expected.Add (new ExpectedItem (ExpectedItem.EType.CHILD_BEGIN, null));
			expected.Add (new ExpectedItem (ExpectedItem.EType.CHILD_END, null));
			expected.Add (new ExpectedItem (ExpectedItem.EType.STRING, ""));
			expected.Add (new ExpectedItem (ExpectedItem.EType.CHILD_BEGIN, null));
			expected.Add (new ExpectedItem (ExpectedItem.EType.CHILD_END, null));
			expected.Add (new ExpectedItem (ExpectedItem.EType.STRING, ""));
			expected.Add (new ExpectedItem (ExpectedItem.EType.CHILD_BEGIN, null));
			expected.Add (new ExpectedItem (ExpectedItem.EType.STRING, ""));
			expected.Add (new ExpectedItem (ExpectedItem.EType.CHILD_BEGIN, null));
			expected.Add (new ExpectedItem (ExpectedItem.EType.CHILD_END, null));
			expected.Add (new ExpectedItem (ExpectedItem.EType.STRING, ""));
			expected.Add (new ExpectedItem (ExpectedItem.EType.CHILD_BEGIN, null));
			expected.Add (new ExpectedItem (ExpectedItem.EType.CHILD_END, null));
			expected.Add (new ExpectedItem (ExpectedItem.EType.CHILD_END, null));
			expected.Add (new ExpectedItem (ExpectedItem.EType.STRING, ""));
			expected.Add (new ExpectedItem (ExpectedItem.EType.CHILD_BEGIN, null));
			expected.Add (new ExpectedItem (ExpectedItem.EType.STRING, "child string"));
			expected.Add (new ExpectedItem (ExpectedItem.EType.STRING, "aaa"));
			expected.Add (new ExpectedItem (ExpectedItem.EType.CHILD_BEGIN, null));
			expected.Add (new ExpectedItem (ExpectedItem.EType.CHILD_END, null));
			expected.Add (new ExpectedItem (ExpectedItem.EType.STRING, "bbb"));
			expected.Add (new ExpectedItem (ExpectedItem.EType.STRING, "ccc"));
			expected.Add (new ExpectedItem (ExpectedItem.EType.CHILD_BEGIN, null));
			expected.Add (new ExpectedItem (ExpectedItem.EType.STRING, "ddd"));
			expected.Add (new ExpectedItem (ExpectedItem.EType.CHILD_END, null));
			expected.Add (new ExpectedItem (ExpectedItem.EType.STRING, ""));
			expected.Add (new ExpectedItem (ExpectedItem.EType.CHILD_BEGIN, null));
			expected.Add (new ExpectedItem (ExpectedItem.EType.CHILD_END, null));
			expected.Add (new ExpectedItem (ExpectedItem.EType.CHILD_END, null));
			expected.Add (new ExpectedItem (ExpectedItem.EType.STRING, "Tab\t Backslash\\ Slash/ Doubleslash// Newline\n Carriagereturn\r Doublequotes\" {}{}{}{}"));
			expected.Add (new ExpectedItem (ExpectedItem.EType.STRING, "quoted string with trailing slash /"));
			expected.Add (new ExpectedItem (ExpectedItem.EType.STRING, "fff ggg"));
			expected.Add (new ExpectedItem (ExpectedItem.EType.STRING, "tralala tro lo lo\ntre lele"));
			expected.Add (new ExpectedItem (ExpectedItem.EType.STRING, "-1213.33"));
			expected.Add (new ExpectedItem (ExpectedItem.EType.STRING, "UnquotedStringAtTheVeryEndOfTheFile"));

			Parser.Parse(
					File.OpenText("test.stob"),
					new Parser.Listener{
						OnChildrenParseStarted = () => {
							Debug.Assert (expected [0].type == ExpectedItem.EType.CHILD_BEGIN, "expected child begin");
							expected.RemoveAt (0);
						},
						OnChildrenParseFinished = () => {
							Debug.Assert (expected [0].type == ExpectedItem.EType.CHILD_END, "expected child end");
							expected.RemoveAt(0);
						},
						OnStringParsed = (str) => {
							Debug.Assert (expected [0].type == ExpectedItem.EType.STRING);
							Debug.Assert (expected [0].str.Equals (str, StringComparison.Ordinal), "expected: " + expected[0].str + " got: " + str);
							expected.RemoveAt (0);
						}
					}
				);
		}

		private static void TestDom(){
			var expectedDom = new List<Node>();

			expectedDom.Add(new Node("ttt"));
			expectedDom.Add(new Node("test string"));
			expectedDom.Add(new Node("anot/her string"));
			expectedDom.Add(new Node("unqu/otedString"));
			expectedDom.Add(new Node("string with empty children list"));
			expectedDom.Add(new Node("unquoted_string_with_empty_children_list"));
			expectedDom.Add(new Node("string_interrupted_by_comment"));
			expectedDom.Add(new Node("string_broken_by_comment"));
			expectedDom.Add(new Node());
			{
				Node n = new Node();
				n.Add(new Node());
				n.Add(new Node());
				expectedDom.Add(n);
			}
			{
				Node n = new Node();
				n.Add(new Node("child string"));
				n.Add(new Node("aaa"));
				n.Add(new Node("bbb"));
				{
					Node n1 = new Node("ccc");
					n1.Add(new Node("ddd"));
					n.Add(n1);
				}
				n.Add(new Node());

				expectedDom.Add(n);
			}
			expectedDom.Add(new Node("Tab\t Backslash\\ Slash/ Doubleslash// Newline\n Carriagereturn\r Doublequotes\" {}{}{}{}"));
			expectedDom.Add(new Node("quoted string with trailing slash /"));
			expectedDom.Add(new Node("fff ggg"));
			expectedDom.Add(new Node("tralala tro lo lo\ntre lele"));
			expectedDom.Add(new Node("-1213.33"));
			expectedDom.Add(new Node("UnquotedStringAtTheVeryEndOfTheFile"));

			var dom = stob.Node.Load (File.OpenText ("test.stob"));

			Debug.Assert(Node.CompareChains(dom, expectedDom));
		}

		private static void TestWritingDom(){
			for(int i = 0; i != 2; ++i){
				var dom = Node.Load(File.OpenText ("test.stob"));

				var ms = new MemoryStream ();
				Node.Write(ms, dom, i == 0);

//				Debug.Write(Encoding.UTF8.GetString (ms.ToArray ()));

				ms.Seek (0, SeekOrigin.Begin);
				var dom1 = Node.Load(new StreamReader(ms));

				Debug.Assert(Node.CompareChains(dom, dom1), "TestWritingDom(): DOMs are not equal");
			}
		}

		public static void Main (string[] args)
		{
			//For assertions to  apper in the console output
			var tl = new System.Diagnostics.ConsoleTraceListener();
			System.Diagnostics.Debug.Listeners.Add ( tl );

			TestParser ();
			TestDom ();
			TestWritingDom ();

			System.Diagnostics.Debug.WriteLine ("TEST FINISHED!");
		}
	}
}
